package com.xyxy.platform.modules.core.utils;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.sift.MDCBasedDiscriminator;
import ch.qos.logback.classic.sift.SiftingAppender;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import ch.qos.logback.core.sift.AppenderFactory;
import ch.qos.logback.core.status.InfoStatus;
import ch.qos.logback.core.status.StatusManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.Charset;

/**
 * 日志工具类
 */
public class LoggerUtils {

    static LoggerContext loggerContext;

    static {
        loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        StatusManager statusManager = loggerContext.getStatusManager();

        if (statusManager != null) {
            statusManager.add(new InfoStatus("Configuring logger", loggerContext));
        }
    }

    public static Logger createTimeLogger(String baseDir, String name, String timeFormat, String logExt) {

        // Set up the filters to ensure things get split as expected
//        LevelFilter traceFilter = new LevelFilter();
//        traceFilter.setContext(loggerContext);
//        traceFilter.setLevel(Level.INFO);
//        traceFilter.setOnMatch(FilterReply.ACCEPT);
//        traceFilter.setOnMismatch(FilterReply.DENY);

        // Set up the trace and error appenders
        RollingFileAppender<ILoggingEvent> rollingFileAppender = new RollingFileAppender<>();
        rollingFileAppender.setContext(loggerContext);
        rollingFileAppender.setName(name);
        rollingFileAppender.setFile(FilenameUtils3.concat(baseDir, name + logExt));

        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setCharset(Charset.forName("UTF-8"));
        encoder.setContext(loggerContext);
        encoder.setPattern("%msg%n");
        encoder.start();

        rollingFileAppender.setEncoder(encoder);

        // Set up the roll over policies and the name when it rolls over
        String savedFilePath =
                FilenameUtils3.concat(baseDir, "saved");
        savedFilePath =
                FilenameUtils3.concat(savedFilePath, name);
        createTimePolicy(rollingFileAppender, savedFilePath, timeFormat, logExt);
//                tracePolicy.setMaxHistory( 30 );
//        rollingFileAppenderTrace.addFilter(traceFilter);

//        traceFilter.start();
        rollingFileAppender.start();

        // attach the rolling file appenders to the logger
        ch.qos.logback.classic.Logger logger = loggerContext.getLogger(name);
        logger.setAdditive(false);
        logger.setLevel(Level.INFO);
        logger.addAppender(rollingFileAppender);

//        StatusPrinter.print(loggerContext);

        return logger;
    }

    public static Logger createTimeSizeLogger(String baseDir, String name, String timeFormat,
                                              String logExt, String maxFileSize) {

        // Set up the filters to ensure things get split as expected
//        LevelFilter traceFilter = new LevelFilter();
//        traceFilter.setContext(loggerContext);
//        traceFilter.setLevel(Level.INFO);
//        traceFilter.setOnMatch(FilterReply.ACCEPT);
//        traceFilter.setOnMismatch(FilterReply.DENY);

        // Set up the trace and error appenders
        RollingFileAppender<ILoggingEvent> rollingFileAppender = new RollingFileAppender<>();
        rollingFileAppender.setContext(loggerContext);
        rollingFileAppender.setName(name);
        rollingFileAppender.setFile(FilenameUtils3.concat(baseDir, name + logExt));

        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setCharset(Charset.forName("UTF-8"));
        encoder.setContext(loggerContext);
        encoder.setPattern("%msg%n");
        encoder.start();

        rollingFileAppender.setEncoder(encoder);

        // Set up the roll over policies and the name when it rolls over
        String savedFilePath =
                FilenameUtils3.concat(baseDir, "saved");
        savedFilePath =
                FilenameUtils3.concat(savedFilePath, name);
        createTimeSizePolicy(rollingFileAppender, savedFilePath, timeFormat,
                logExt, maxFileSize);
//                tracePolicy.setMaxHistory( 30 );
//        rollingFileAppenderTrace.addFilter(traceFilter);

//        traceFilter.start();
        rollingFileAppender.start();

        // attach the rolling file appenders to the logger
        ch.qos.logback.classic.Logger logger = loggerContext.getLogger(name);
        logger.setAdditive(false);
        logger.setLevel(Level.INFO);
        logger.addAppender(rollingFileAppender);

//        StatusPrinter.print(loggerContext);

        return logger;
    }

    public static Logger createTimeSiftLogger(final String baseDir, String name, final String timeFormat,
                                              final String logExt,
                                              final String keyName,
                                              final String defaultValue,
                                              final String maxFileSize) {
        SiftingAppender sa = new SiftingAppender();
        sa.setName(name);
        sa.setContext(loggerContext);

        MDCBasedDiscriminator discriminator = new MDCBasedDiscriminator();
        discriminator.setKey(keyName);
        discriminator.setDefaultValue(defaultValue);
        discriminator.start();

        sa.setDiscriminator(discriminator);

        sa.setAppenderFactory(new AppenderFactory<ILoggingEvent>() {

            @Override
            public Appender<ILoggingEvent> buildAppender(Context context, String discriminatingValue) throws JoranException {
                RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
                appender.setName("SIFT-FILE-" + discriminatingValue);
                appender.setContext(context);
                String filePath = FilenameUtils3.concat(baseDir, discriminatingValue + logExt);
                appender.setFile(filePath);

                String savedFilePath =
                        FilenameUtils3.concat(baseDir, "saved");
                savedFilePath =
                        FilenameUtils3.concat(savedFilePath, discriminatingValue);
                createTimeSizePolicy(appender, savedFilePath,
                        timeFormat, logExt, context, maxFileSize);

                PatternLayoutEncoder encoder = new PatternLayoutEncoder();
                encoder.setCharset(Charset.forName("UTF-8"));
                encoder.setContext(loggerContext);
                encoder.setPattern("%msg%n");
                encoder.start();
                appender.setEncoder(encoder);

                appender.start();
                return appender;
            }
        });

        sa.start();

        // attach the rolling file appenders to the logger
        ch.qos.logback.classic.Logger logger = loggerContext.getLogger(name);
        logger.setAdditive(false);
        logger.setLevel(Level.INFO);
        logger.addAppender(sa);

        return logger;
    }

    private static <E> TimeBasedRollingPolicy<ILoggingEvent> createTimePolicy(RollingFileAppender<E> appender,
                                                                              String basePath,
                                                                              String timeFormat,
                                                                              String logExt) {
        TimeBasedRollingPolicy<ILoggingEvent> policy = new TimeBasedRollingPolicy<>();
        policy.setContext(loggerContext);
        policy.setFileNamePattern(basePath + "-%d{" + timeFormat + "}" + logExt);
//      policy.setMaxHistory( 30 );
        policy.setParent(appender);
        appender.setRollingPolicy(policy);
        policy.start();
        return policy;
    }

    private static <E> TimeBasedRollingPolicy<ILoggingEvent> createTimeSizePolicy(RollingFileAppender<E> appender,
                                                                                  String basePath,
                                                                                  String timeFormat,
                                                                                  String logExt,
                                                                                  String maxSize) {
        return createTimeSizePolicy(appender, basePath, timeFormat, logExt, appender.getContext(), maxSize);
    }

    private static <E> TimeBasedRollingPolicy<ILoggingEvent> createTimeSizePolicy(RollingFileAppender<E> appender,
                                                                                  String basePath,
                                                                                  String timeFormat,
                                                                                  String logExt, Context context,
                                                                                  String maxSize) {
        TimeBasedRollingPolicy<ILoggingEvent> policy =
                createTimePolicy(appender, basePath,
                        timeFormat, "-%i" + logExt);

        SizeAndTimeBasedFNATP<ILoggingEvent> innerPolicy = new SizeAndTimeBasedFNATP<>();
        innerPolicy.setContext(context);
        innerPolicy.setMaxFileSize(maxSize);
        innerPolicy.setTimeBasedRollingPolicy(policy);
        innerPolicy.start();

        policy.setTimeBasedFileNamingAndTriggeringPolicy(innerPolicy);

        policy.start();
        appender.setRollingPolicy(policy);
        return policy;
    }
}
